﻿/**
 * @ngdoc overview
 * @name crm.services
 * @description
 *   CRM模块服务
 */

angular.module('crm.services', [])

/**
 * @property
 * @type {Object}
 * @description
 *   销售简报时间取值
 */
.constant('CRM_REPORT_TIMETYPES', [{
  text: '本月',
  type: 5
}, {
  text: '上月',
  type: 6
}, {
  text: '本周',
  type: 3
}, {
  text: '上周',
  type: 4
}])

/**
 * @property
 * @todo 这里的值由后端统一管理会比较合适
 * @type Object
 * @description
 *   联系人扩展字段
 */
.constant('CRM_CONTACT_EXTEND', {
  'phone': '电话',
  'email': '邮箱',
  'mobile': '手机',
  'address': '地址',
  'weibo': '微博',
  'qq': 'QQ',
  'weixin': '微信'
})

/**
 * @ngdoc service
 * @name  crm.services.CRMContact
 * @description
 *   CRM 通用服务
 */
.factory('CRM', function($http, Settings, Utils) {
  return {
    /**
     * @ngdoc     method
     * @name      crm.services.CRM#tagList
     * @methodOf  crm.services.CRM
     * @description
     *    获取标签设置
     *    `params.module`  {string}  获取指定模块的标签，可选值有 client、contact、opportunity、event、contract、receipt
     * @returns {HttpPromise}   HttpPromise
     */
    tagList: function(params) {
      return Utils.postJsonData(Settings.hostUrl + '?r=crm/api/taglist', params);
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRM#getReport
     * @methodOf  crm.services.CRM
     * @param     {object}  [params]  查询参数
     * @description
     *    获取销售简报
     *    `time`  {number}  时间范围，3本周，4上周，5本月，6上月
     * 
     *    [接口文档](http://doc.ibos.cn/index.php?s=/2&page_id=247)
     * @returns {HttpPromise}   HttpPromise
     */
    getReport: function(params) {
      return $http.post(Settings.hostUrl + '?r=crm/api/getsalereport', params);
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRM#getTarget
     * @methodOf  crm.services.CRM
     * @param     {object}  [params]  查询参数
     * @description
     *    获取个人业绩目标
     *    `uid`   {string}  用户uid，如u_1
     *    `year`  {string}  年份
     *    `type`  {number}  1新增客户数 2新增商机数 3新增合同数 4新增收款金额 5新增合同金额 6新增商机金额
     * 
     *    [接口文档](http://doc.ibos.cn/index.php?s=/2&page_id=185)
     * @returns {HttpPromise}   HttpPromise
     */
    getTarget: function(params) {
      return $http.post(Settings.hostUrl + '?r=crm/target/gettarget', params);
    },
    
    /**
     * @ngdoc     method
     * @name      crm.services.CRM#getOppSurvey
     * @methodOf  crm.services.CRM
     * @param     {object}  [params]  查询参数
     * @description
     *    获取商机概况
     * 
     *    [接口文档](http://doc.ibos.cn/index.php?s=/2&page_id=248)
     * @returns {HttpPromise}   HttpPromise
     */
    getOppSurvey: function(params) {
      return $http.post(Settings.hostUrl + '?r=crm/api/getoppsurvey', params);
    }

  }
})

/**
 * @ngdoc service
 * @name  crm.services.CRMContact
 * @description
 *   CRM 联系人服务
 */
.factory('CRMContact', function($http, Utils, Settings, CRM) {
  var CRMContact = {
    /**
     * @ngdoc     method
     * @name      crm.services.CRMContact#avatar
     * @methodOf  crm.services.CRMContact
     * @description
     *    上传联系人头像
     *
     * @param   {File}          file  文件对象
     * @returns {HttpPromise}   HttpPromise
     */
    avatar: function(file) {
      var formData = new FormData();
      formData.append('Filedata', file);
      return Utils.postFormData(Settings.hostUrl + '?r=crm/api/contactavatar', formData);
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMContact#list
     * @methodOf  crm.services.CRMContact
     * @description
     *    获取联系人列表
     *    
     *    - params.range    {string}  筛选范围，my：我的|all：全部，默认all
     *    - params.tags     {array}   标签条件，不填则没有限制
     *    - params.keyword  {string}  联系人名字模糊搜索
     *    - params.limit    {number}  每次获取条数
     *    - params.offset   {number}  获取数据的起始点
     *    - params.order    {object}  按公司company，姓名name，创建时间createtime排序，默认按名字正向排序，格式{'createtime':1}，1表示正向排序，0表示倒向排序，支持多个排序，放在前面的优先级高，不在说明里的字段会被忽略
     *
     * @param   {Object}        params  请求参数
     * @returns {HttpPromise}   HttpPromise
     */
    list: function(params) {
      return Utils.postJsonData(Settings.hostUrl + '?r=crm/api/contactlist', params);
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMContact#create
     * @methodOf  crm.services.CRMContact
     * @description
     *    创建联系人
     *
     * @param   {Object}        data    表单数据
     * @returns {HttpPromise}   HttpPromise
     */
    create: function(data) {
      return Utils.postJsonData(Settings.hostUrl + '?r=crm/api/contactadd', data);
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMContact#create
     * @methodOf  crm.services.CRMContact
     * @description
     *    更新联系人信息
     *
     * @param   {Object}        data    表单数据
     * @returns {HttpPromise}   HttpPromise
     */
    update: function(data) {
      return Utils.postJsonData(Settings.hostUrl + '?r=crm/api/contactedit', data);
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMContact#view
     * @methodOf  crm.services.CRMContact
     * @description
     *    获取联系人详情
     *    `params.contactid`  {string}  联系人 id
     * @param   {Object}        params    请求参数
     * @returns {HttpPromise}   HttpPromise
     */
    view: function(params) {
      return Utils.postJsonData(Settings.hostUrl + '?r=crm/api/contactdetail', params);
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMContact#remove
     * @methodOf  crm.services.CRMContact
     * @description
     *    删除联系人
     *    `params.contactid`  {string}  联系人 id
     * @param   {Object}        params    请求参数
     * @returns {HttpPromise}   HttpPromise
     */
    remove: function(params) {
      return Utils.postJsonData(Settings.hostUrl + '?r=crm/api/contactremove', params);
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMContact#tagList
     * @methodOf  crm.services.CRMContact
     * @description
     *    获取联系人模块标签设置
     * @returns {HttpPromise}   HttpPromise
     */
    tagList: function() {
      return CRM.tagList({
        module: 'contact'
      });
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMContact#tagList
     * @methodOf  crm.services.CRMContact
     * @description
     *    获取联系人选择窗口数据
     *    params.type  {string}  类型，可选 client、opp、event
     *    params.cid
     *    params.oid
     *    params.eventid
     * @param   {object}        params
     * @returns {HttpPromise}   HttpPromise
     */
    select: function(params) {
      return Utils.postJsonData(Settings.hostUrl + '?r=crm/api/contactselect', params);
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMContact#related
     * @methodOf  crm.services.CRMContact
     * @description
     *    关联联系人到客户、商机、事件
     *    `params.type`       {string}  关联类型
     *    `params.contactid`  {array}   联系人id
     *    `params.cid`        {string}  关联目标数据，多选一
     *    `params.oid`        {string}  关联目标数据，多选一
     * @param   {Object}        params    请求参数
     * @returns {HttpPromise}   HttpPromise
     */
    related: function(params) {
      return Utils.postJsonData(Settings.hostUrl + '?r=crm/api/contactrelated', params);
    }
  };

  return CRMContact;
})

/**
 * @ngdoc service
 * @name  crm.services.CRMClient
 * @description
 *   CRM 客户服务
 */
.factory('CRMClient', function($http, Utils, Settings, CRM) {
  var CRMClient = {
    /**
     * @ngdoc     method
     * @name      crm.services.CRMClient#tagList
     * @methodOf  crm.services.CRMClient
     * @description
     *    获取客户模块标签设置
     * @returns {HttpPromise}   HttpPromise
     */
    tagList: function() {
      return CRM.tagList({
        module: 'client'
      });
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMClient#list
     * @methodOf  crm.services.CRMClient
     * @description
     *    获取客户列表
     *    
     *    - params.range    {string}  筛选范围，my：我的|all：全部，默认all
     *    - params.tags     {array}   标签条件，不填则没有限制
     *    - params.keyword  {string}  联系人名字模糊搜索
     *    - params.limit    {number}  每次获取条数
     *    - params.offset   {number}  获取数据的起始点
     *
     * @param   {Object}        params  请求参数
     * @returns {HttpPromise}   HttpPromise
     */
    list: function(params) {
      return Utils.postJsonData(Settings.hostUrl + '?r=crm/api/clientlist', params);
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMClient#create
     * @methodOf  crm.services.CRMClient
     * @description
     *    创建客户
     *
     * @param   {Object}        data    表单数据
     * @returns {HttpPromise}   HttpPromise
     */
    create: function(data) {
      return Utils.postJsonData(Settings.hostUrl + '?r=crm/api/clientadd', data);
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMClient#create
     * @methodOf  crm.services.CRMClient
     * @description
     *    更新客户信息
     *
     * @param   {Object}        data    表单数据
     * @returns {HttpPromise}   HttpPromise
     */
    update: function(data) {
      return Utils.postJsonData(Settings.hostUrl + '?r=crm/api/clientedit', data);
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMClient#view
     * @methodOf  crm.services.CRMClient
     * @description
     *    获取客户详情
     *    `params.cid`  {string}  客户 id
     * @returns {HttpPromise}   HttpPromise
     */
    view: function(params) {
      return Utils.postJsonData(Settings.hostUrl + '?r=crm/api/clientdetail', params);
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMClient#remove
     * @methodOf  crm.services.CRMClient
     * @description
     *    删除客户
     *    `params.cid`  {string}  客户 id
     * @returns {HttpPromise}   HttpPromise
     */
    remove: function(params) {
      return Utils.postJsonData(Settings.hostUrl + '?r=crm/api/clientremove', params);
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMClient#select
     * @methodOf  crm.services.CRMClient
     * @description
     *    获取客户选择器数据
     * @returns {HttpPromise}   HttpPromise
     */
    select: function(params) {
      return Utils.postJsonData(Settings.hostUrl + '?r=crm/api/clientselect', params);
    }
  };

  return CRMClient;
})

/**
 * @ngdoc service
 * @name  crm.services.CRMOpportunity
 * @description
 *   CRM 商机服务
 */
.factory('CRMOpportunity', function($http, Utils, Settings, CRM) {
  var CRMOpportunity = {
    /**
     * @ngdoc     method
     * @name      crm.services.CRMOpportunity#tagList
     * @methodOf  crm.services.CRMOpportunity
     * @description
     *    获取商机模块标签设置
     * @returns {HttpPromise}   HttpPromise
     */
    tagList: function() {
      return CRM.tagList({
        module: 'opportunity'
      });
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMOpportunity#list
     * @methodOf  crm.services.CRMOpportunity
     * @description
     *    获取商机列表
     *    
     *    - params.range    {string}  筛选范围，my：我的|all：全部，默认all
     *    - params.tags     {array}   标签条件，不填则没有限制
     *    - params.keyword  {string}  联系人名字模糊搜索
     *    - params.limit    {number}  每次获取条数
     *    - params.offset   {number}  获取数据的起始点
     *
     * @param   {Object}        params  请求参数
     * @returns {HttpPromise}   HttpPromise
     */
    list: function(params) {
      return Utils.postJsonData(Settings.hostUrl + '?r=crm/api/opplist', params);
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMOpportunity#create
     * @methodOf  crm.services.CRMOpportunity
     * @description
     *    创建商机
     *
     * @param   {Object}        data    表单数据
     * @returns {HttpPromise}   HttpPromise
     */
    create: function(data) {
      return Utils.postJsonData(Settings.hostUrl + '?r=crm/api/oppadd', data);
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMOpportunity#create
     * @methodOf  crm.services.CRMOpportunity
     * @description
     *    更新商机信息
     *
     * @param   {Object}        data    表单数据
     * @returns {HttpPromise}   HttpPromise
     */
    update: function(data) {
      return Utils.postJsonData(Settings.hostUrl + '?r=crm/api/oppedit', data);
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMOpportunity#view
     * @methodOf  crm.services.CRMOpportunity
     * @description
     *    获取商机详情
     *    `params.oid`  {string}  商机id
     *    
     * @returns {HttpPromise}   HttpPromise
     */
    view: function(params) {
      return Utils.postJsonData(Settings.hostUrl + '?r=crm/api/oppdetail', params);
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMOpportunity#remove
     * @methodOf  crm.services.CRMOpportunity
     * @description
     *    删除商机
     *    `params.oid`  {string}  商机id
     *    
     * @returns {HttpPromise}   HttpPromise
     */
    remove: function(params) {
      return Utils.postJsonData(Settings.hostUrl + '?r=crm/api/oppremove', params);
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMOpportunity#select
     * @methodOf  crm.services.CRMOpportunity
     * @description
     *    获取商机选择数据
     *    `params.cid`  {string}  客户id
     *    
     * @returns {HttpPromise}   HttpPromise
     */
    select: function(params) {
      return Utils.postJsonData(Settings.hostUrl + '?r=crm/api/oppselect', params);
    }
  };

  return CRMOpportunity;
})

/**
 * @ngdoc service
 * @name  crm.services.CRMEvent
 * @description
 *   CRM 事件服务
 */
.factory('CRMEvent', function($http, Utils, Settings, CRM) {
  var CRMEvent = {
    /**
     * @ngdoc     method
     * @name      crm.services.CRMEvent#tagList
     * @methodOf  crm.services.CRMEvent
     * @description
     *    获取事件模块标签设置
     * @returns {HttpPromise}   HttpPromise
     */
    tagList: function() {
      return CRM.tagList({
        module: 'event'
      });
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMEvent#list
     * @methodOf  crm.services.CRMEvent
     * @description
     *    获取事件列表
     *    
     *    - params.range    {string}  筛选范围，my：我的|all：全部，默认all
     *    - params.tags     {array}   标签条件，不填则没有限制
     *    - params.keyword  {string}  联系人名字模糊搜索
     *    - params.limit    {number}  每次获取条数
     *    - params.offset   {number}  获取数据的起始点
     *
     * @param   {Object}        params  请求参数
     * @returns {HttpPromise}   HttpPromise
     */
    list: function(params) {
      return Utils.postJsonData(Settings.hostUrl + '?r=crm/api/eventlist', params);
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMEvent#create
     * @methodOf  crm.services.CRMEvent
     * @description
     *    创建事件
     *
     * @param   {Object}        data    表单数据
     * @returns {HttpPromise}   HttpPromise
     */
    create: function(data) {
      return Utils.postJsonData(Settings.hostUrl + '?r=crm/api/eventadd', data);
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMEvent#create
     * @methodOf  crm.services.CRMEvent
     * @description
     *    更新事件信息
     *
     * @param   {Object}        data    表单数据
     * @returns {HttpPromise}   HttpPromise
     */
    update: function(data) {
      return Utils.postJsonData(Settings.hostUrl + '?r=crm/api/eventedit', data);
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMEvent#view
     * @methodOf  crm.services.CRMEvent
     * @description
     *    获取事件详情
     * @returns {HttpPromise}   HttpPromise
     */
    view: function(params) {
      return Utils.postJsonData(Settings.hostUrl + '?r=crm/api/eventdetail', params);
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMEvent#remove
     * @methodOf  crm.services.CRMEvent
     * @description
     *    删除事件
     * @returns {HttpPromise}   HttpPromise
     */
    remove: function(params) {
      return Utils.postJsonData(Settings.hostUrl + '?r=crm/api/eventremove', params);
    }
  };

  return CRMEvent;
})

/**
 * @ngdoc service
 * @name  crm.services.CRMUtils
 * @description
 *   CRM 工具函数
 */
.factory('CRMUtils', function($rootScope, $window, $ionicHistory, $ionicLoading, $ionicModal, $ionicViewSwitcher, dateFilter, mapFilter, Utils, IbPopup, CRMContact, CRMClient, CRMOpportunity, CRMEvent) {

  return {
    /**
     * @ngdoc     method
     * @name      crm.services.CRMUtils#buildContactFormData
     * @methodOf  crm.services.CRMUtils
     * @description
     *    预处理联系人表单数据
     * @returns {HttpPromise}   HttpPromise
     */
    buildContactFormData: function(data) {
      return angular.extend({}, data, {
        birthday: dateFilter(data.birthday, 'yyyy-MM-dd'),
        cid: data.client.cid,
        client: null
      });
    },

    // 移除包装函数
    wrapRemovePromise: function(promise, clearState) {
      $ionicLoading.show();
      promise.success(function(res) {
          if (res.isSuccess) {
            $ionicHistory.clearCache([clearState]).then(function() {
              //@Note: 此处不使用 history.go(-2) 是由于动画方向不同
              $ionicViewSwitcher.nextDirection('back')
              $window.history.go(-2)
              // $ionicHistory.goBack(-2)
            });
          } else {
            IbPopup.alert({
              title: res.msg
            });
          }
        })
        .finally($ionicLoading.hide);
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMUtils#confirmRemoveContact
     * @methodOf  crm.services.CRMUtils
     * @description
     *    确认删除联系人
     * @param   {object}  params  作为 CRMContact.remove 方法的参数直接调用
     * @returns {HttpPromise}   HttpPromise
     */
    confirmRemoveContact: function(params) {
      var that = this;
      IbPopup.confirm({
          title: '确定要删除当前联系人？'
        })
        .then(function(ok) {
          if (ok) {
            that.wrapRemovePromise(CRMContact.remove(params), 'crm.contact')
          }
        });
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMUtils#confirmRemoveClient
     * @methodOf  crm.services.CRMUtils
     * @description
     *    确认删除客户
     * @param   {object}  params  作为 CRMClient.remove 方法的参数直接调用
     * @returns {HttpPromise}   HttpPromise
     */
    confirmRemoveClient: function(params) {
      var that = this;
      return IbPopup.confirm({
          title: '确定要删除当前客户？'
        })
        .then(function(ok) {
          if (ok) {
            that.wrapRemovePromise(CRMClient.remove(params), 'crm.client')
          }
        });
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMUtils#confirmRemoveClient
     * @methodOf  crm.services.CRMUtils
     * @description
     *    确认删除商机
     * @param   {object}  params  作为 CRMOpportunity.remove 方法的参数直接调用
     * @returns {HttpPromise}   HttpPromise
     */
    confirmRemoveOpportunity: function(params) {
      var that = this;
      return IbPopup.confirm({
          title: '确定要删除当前商机？'
        })
        .then(function(ok) {
          if (ok) {
            that.wrapRemovePromise(CRMOpportunity.remove(params), 'crm.opportunity')
          }
        });
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMUtils#confirmRemoveEvent
     * @methodOf  crm.services.CRMUtils
     * @description
     *    确认删除商机
     * @param   {object}  params  作为 CRMEvent.remove 方法的参数直接调用
     * @returns {HttpPromise}   HttpPromise
     */
    confirmRemoveEvent: function(params) {
      var that = this;
      return IbPopup.confirm({
          title: '确定要删除当前事件？'
        })
        .then(function(ok) {
          if (ok) {
            that.wrapRemovePromise(CRMEvent.remove(params), 'crm.event')
          }
        });
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMUtils#buildOpportunityFormData
     * @methodOf  crm.services.CRMUtils
     * @description
     *    预处理联系人表单数据
     * @returns {HttpPromise}   HttpPromise
     */
    buildOpportunityFormData: function(data) {
      return angular.extend({}, data, {
        createtime: dateFilter(data.createtime, 'yyyy-MM-dd HH:mm:ss'),
        expectendtime: dateFilter(data.expectendtime, 'yyyy-MM-dd HH:mm:ss')
      });
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMUtils#openClientModal
     * @methodOf  crm.services.CRMUtils
     * @todo  openClientModal、openOpportunityModal、openContactModal 有大量重复逻辑，可以整理
     * @description
     *    打开客户选择窗口
     *    opts.cid       {string}    当前选中的客户id
     *    opts.callback  {function}  确认后回调
     * @param   {object}  opts  参数
     * @returns {HttpPromise}   HttpPromise
     */
    openClientModal: function(opts) {
      var that = this;
      var scope = this.clientScope;

      opts = opts || {};

      function fetch() {
        CRMClient.select().success(function(res) {
          if (res.isSuccess) {
            that.clientScope.clients = res.data;
            that.clientScope.clients.forEach(function(client) {
              client.firstLetter = client.firstCase.charAt(0).toUpperCase()
            })
          }
        });
      }

      if (scope) {
        scope.cid = opts.cid;
        scope.opts = opts;
        fetch()
        return this.clientScope.modal.show();
      }

      scope = this.clientScope = $rootScope.$new(true);
      scope.opts = opts;

      $ionicModal.fromTemplateUrl('templates/crm/select-client.html', {
        scope: scope
      }).then(function(modal) {
        fetch()
        modal.show();
        that.clientScope.cid = scope.opts.cid;
        that.clientScope.select = function(client) {
          scope.opts.callback && scope.opts.callback(client);
          modal.hide();
        };
        that.clientScope.modal = modal;
        that.clientScope.$on('$destroy', modal.remove.bind(modal));
        $rootScope.$on('$stateChangeSuccess', modal.hide.bind(modal))
      });
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMUtils#openOpportunityModal
     * @methodOf  crm.services.CRMUtils
     * @description
     *    打开商机选择窗口
     *    opts.selected   {string}    当前选中的商机id
     *    opts.callback   {function}  确认后回调
     * @param   {object}  opts  参数
     * @returns {HttpPromise}   HttpPromise
     */
    openOpportunityModal: function(opts) {
      var that = this;
      var scope = this.oppScope;

      opts = opts || {};

      function fetch() {
        CRMOpportunity.select(opts.params).success(function(res) {
          if (res.isSuccess) {
            scope.opps = res.data;
          }
        });
      }

      if (scope) {
        scope.selected = opts.selected;
        scope.opts = opts;
        fetch();
        return scope.modal.show();
      }

      scope = this.oppScope = $rootScope.$new(true);
      scope.opts = opts;

      $ionicModal.fromTemplateUrl('templates/crm/select-opportunity.html', {
        scope: scope
      }).then(function(modal) {
        fetch()
        modal.show();
        scope.selected = scope.opts.selected;
        scope.select = function(opp) {
          scope.opts.callback && scope.opts.callback(opp);
          modal.hide();
        };
        scope.modal = modal;
        scope.$on('$destroy', modal.remove.bind(modal));
        $rootScope.$on('$stateChangeSuccess', modal.hide.bind(modal))
      });
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMUtils#openClientModal
     * @methodOf  crm.services.CRMUtils
     * @description
     *    打开联系人选择窗口
     *    opts.selected  {array}   当前选中的联系人数据
     *    opts.callback  {function}  确认后回调
     * @param   {object}  opts  参数
     * @returns {HttpPromise}   HttpPromise
     */
    openContactModal: function(opts) {
      var that = this;
      var scope = this.contactScope;
      opts = opts || {};

      function fetch() {
        CRMContact.select(scope.opts.params).success(function(res) {
          if (res.isSuccess) {
            scope.contacts = res.data.list;
            scope.restoreSelected(scope.opts.selected);
          }
        });
      }

      if (scope) {
        scope.opts = opts;
        fetch();
        return scope.modal.show();
      }

      scope = this.contactScope = $rootScope.$new(true);
      scope.opts = opts;
      // 获取选中值数组
      scope.getSelected = function() {
        if (this.contacts && this.contacts.length) {
          return this.contacts.filter(function(contact) {
            return contact.checked;
          });
        } else {
          return [];
        }
      };
      // 还原初始选中值
      scope.restoreSelected = function(selectedIds) {
        if (scope.contacts && scope.contacts.length) {
          // 如果有传递初始值，则匹配还原
          if (selectedIds && selectedIds.length) {
            scope.contacts.forEach(function(contact) {
              if (selectedIds.indexOf(contact.contactid) !== -1) {
                contact.checked = true;
              }
            });
            // 如果没有，则清空所有选中项
          } else {
            scope.contacts.forEach(function(contact) {
              delete contact.checked;
            });
          }
        }

      };
      scope.save = function() {
        scope.opts.callback && scope.opts.callback(scope.getSelected());
        scope.modal.hide();
      };

      $ionicModal.fromTemplateUrl('templates/crm/select-contact.html', {
        scope: scope
      }).then(function(modal) {
        scope.modal = modal;
        scope.$on('$destroy', modal.remove.bind(modal));
        $rootScope.$on('$stateChangeSuccess', modal.hide.bind(modal))
        fetch();
        modal.show();
      });
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMUtils#openAttachModal
     * @methodOf  crm.services.CRMUtils
     * @description
     *    打开客户关联数据窗口
     */
    openAttachModal: function(scope) {
      var that = this;
      scope.__attachOpts = scope.__attachOpts || {};
      scope.__attachOpts = angular.extend({
        newEvent: true,
        newOpp: true,
        newContact: true,
        attachContact: true
      }, scope.__attachOpts);

      if (scope.clientAttachModal) return scope.clientAttachModal.show();

      $ionicModal.fromTemplateUrl('templates/crm/attach-modal.html', {
        scope: scope,
        animation: 'fade-in'
      }).then(function(modal) {
        modal.hideDelay = 1;
        modal.show();
        scope.clientAttachModal = modal;
        scope.$on('$ionicView.leave', modal.hide.bind(modal));
        scope.$on('$destroy', modal.remove.bind(modal));
      });
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMUtils#selectContactToClient
     * @methodOf  crm.services.CRMUtils
     * @description
     *    选择联系人并关联到客户
     *    
     * @param   {string}    cid       客户id
     * @param   {array}     selected  当前默认选中的 contactid 组
     * @param   {function}  selected  成功回调
     */
    selectContactToClient: function(cid, selected, onSuccess) {
      this.openContactModal({
        selected: selected,
        params: {
          type: 'client'
        },
        callback: function(selected) {
          $ionicLoading.show();
          CRMContact.related({
              type: 'client',
              cid: cid,
              contactid: mapFilter(selected, 'contactid')
            })
            .success(onSuccess)
            .success(Utils.serverWarning)
            .finally($ionicLoading.hide);
        }
      });
    },

    initTagsToForm: function(form, tagGroups) {
      form.tags = form.tags || {};
      angular.forEach(tagGroups, function(tagGroup) {
        if (!form.tags[tagGroup.groupid]) {
          form.tags[tagGroup.groupid] = tagGroup.taglist[0].tagid;
        }
      });
    },

    /**
     * @ngdoc     method
     * @name      crm.services.CRMUtils#setTagsToForm
     * @methodOf  crm.services.CRMUtils
     * @description
     *    将后端返回的标签格式转化为表单可用格式
     *    
     * @param   {object}    form  表单模型
     * @param   {object}    tags  标签信息
     * @param   {function}  selected  成功回调
     */
    setTagsToForm: function(form, tags) {
      if (form && tags && tags.length) {
        form.tags = {};
        angular.forEach(tags, function(tag) {
          form.tags[tag.groupid] = tag.tag.tagid;
        });
      }
      return form;
    },

    formValidateError: function(res) {
      if (!res.isSuccess) {
        if (res.data && res.data.error) {
          IbPopup.alert({
            title: mapFilter(res.data.error).join('<br>')
          });
        } else {
          IbPopup.alert({
            title: res.msg
          });
        }
      }
    }
  }
})

/**
 * @ngdoc filter
 * @name crm.services.filter:groupAndOrder
 * @function
 * @description
 *  分组并按分组索引排序，返回排序后的索引数组 arr，并在 arr.grouped 中引用分组数据
 *
 * @param   {array}             arr        需要分组排序的数组
 * @param   {string|function}   groupBy    分组依据字段
 * @param   {boolean}           orderDesc  是否倒序
 * @returns {array}   分组排序结果
 */
.filter('groupAndOrder', function(groupByFilter) {
  return function(arr, groupBy, orderDesc) {
    var keys = []
    if(arr && arr.length) {
      var grouped = groupByFilter(arr, groupBy);
      
      keys = Object.keys(grouped);
      keys.sort(function(a, b) {
        return (orderDesc ? b > a : a > b) ? 1 : -1;
      });
      keys.grouped = grouped
    }
    return keys;
  }
})

.filter('mapMultiply', function() {
  return function(arr, multi) {
    multi = multi || 10
    return arr.map(function(num) {
      return num * multi
    })
  }
})

/**
 * @ngdoc     directive
 * @name      crm.services.directive:crmContactItem
 * @restrict  E
 * @description
 *   CRM 联系人模板指令
 *   `mode`  {string}  支持 view|attach|edit 三种值，排版不一样，值为 edit 时支持 onRemove 回调
 * @param  {object}  contact  联系人数据
 */
.directive('crmContactItem', function() {
  return {
    restrict: 'E',
    scope: {
      mode: '@',
      onRemove: '&',
      contact: '='
    },
    templateUrl: 'templates/crm/contact-item.html',
    replace: true,
    // transclude: true,
    link: angular.noop
  };
})

/**
 * @ngdoc     directive
 * @name      crm.services.directive:crmEventItem
 * @restrict  E
 * @description
 *   CRM 事件模板指令
 *  
 * @param  {object}  ev  事件
 */
.directive('crmEventItem', function() {
  return {
    restrict: 'E',
    replace: true,
    scope: {
      ev: '='
    },
    templateUrl: 'templates/crm/event-item.html',
    transclude: true,
    link: angular.noop
  };
})

/**
 * @ngdoc     directive
 * @name      crm.services.directive:crmOppItem
 * @restrict  E
 * @description
 *   CRM 商机模板指令
 *  
 * @param  {object}  opp  商机数据
 */
.directive('crmOppItem', function() {
  return {
    restrict: 'E',
    replace: true,
    scope: {
      opp: '='
    },
    templateUrl: 'templates/crm/opportunity-item.html',
    transclude: true,
    link: angular.noop
  };
})

/**
 * @ngdoc     directive
 * @name      ibosApp.directives.directive:clock
 * @element   ANY
 * @restrict  A
 * @description
 *  仪表盘进度
 *
 */
.directive('clock', function($timeout) {
  return {
    restrict: 'A',
    link: function($scope, $element, $attrs) {
      var ele = $element[0],
        attr = $attrs.$attr,
        angle;

      $scope.$watch('percent', function(percent) {
        if (percent) {
          //此处按旋转角度180º计算
          if (attr.plus === 'plus') {
            //角度从0度开始计算
            angle = percent !== 0 ? percent * 1.8 : 0;
          } else {
            //角度从-45度开始计算
            angle = percent === 0 ? -45 : (percent * 1.8 - 45);
          }
          ['transform', 'OTransform', 'msTransform', 'MozTransform', 'webkitTransform'].forEach(function(key) {
            ele.style[key] = 'rotate(' + angle + 'deg)';
          });
        }
      });
    }
  };
})

/**
 * @ngdoc    directive
 * @name     crm.services.directive:searchTabBar
 * @element  ionHeaderBar
 * @restrict A
 * @description
 *   tab 与 search 功能合并工具条
 *   @param tabs        `expression` tab 项数组
 *   @param searchModal `expression` SearchModal 实例
 *   @param onTab       `expression` tab 回调
 */
.directive('searchTabBar', function(SearchModal) {
  return {
    templateUrl: 'templates/crm/search-tab-bar.html',
    scope: {
      tabs: '=searchTabBar',
      searchModal: '=',
      onTab: '&'
    },
    compile: function(element, attrs) {
      element.addClass('search-tab-bar')

      // link
      return function($scope, $element, $attrs) {
        $scope.tabTo = function($index) {
          $scope.activeIndex = $index
          $scope.onTab({
            $tab: $scope.tabs[$index]
          })
        }
        $scope.tabTo(0)
      }
    }
  }
})

/**
 * @ngdoc    directive
 * @name     crm.services.directive:tagsSelector
 * @element  ANY
 * @restrict A
 * @description
 *   标签选择器
 */
.directive('crmFilter', function($compile, $ionicTemplateLoader, Utils) {
  return {
    scope: {
      filterGroups: '=',
      onSelect: '='
    },
    replace: true,
    templateUrl: 'templates/crm/crm-filter-menu.html',
    compile: function(element) {
      // @p.s 此处放置空 ng-click 是为了有点击效果
      // element.attr('ng-click', '')

      // link
      return function($scope, $element, $attrs, $ngModelCtrl) {
        $scope.filterShown = false
        $scope.selectFilterItem = function(item, filterGroup) {
          filterGroup.selected = filterGroup.items.indexOf(item)
          $scope.onSelect(item, filterGroup)
        }
      }
    }

  }
})

/**
 * @ngdoc    directive
 * @name     crm.services.directive:crmUser
 * @element  ANY
 * @restrict ECMA
 * @description
 *   CRM 用户信息组
 */
.directive('crmUser', function() {
  return {
    template: '<span class="crm-user"> ' +
      '<img avatar="{{ uid | avatar | defaultAvatar }}"> ' +
      '<span>{{ uid | userInfo:\'realname\' }}</span> ' +
      '</span>',
    replace: true,
    scope: {
      uid: '@'
    },
    link: angular.noop
  }
})

/**
 * @ngdoc    directive
 * @name     crm.services.directive:crmTagsSection
 * @element  ANY
 * @restrict ECMA
 * @description
 *   CRM 标签组预览文本
 */
.directive('crmTagsSection', function() {
  return {
    template: '<span class="crm-tags-section"> ' +
      '<i class="crm-icon-tag"></i> ' +
      '<span ng-repeat="tag in tags">{{ tag.tag.name }}{{ $last ? \'\' : \'；\' }}</span> ' +
      '</span>',
    replace: true,
    scope: {
      tags: '='
    },
    link: angular.noop
  }
})

.directive('crmEmptyTip', function() {
  return {
    template: '<div class="list-empty-tip"> ' +
      '<i class="news-icon-empty"></i> ' +
      '<p class="margin-top coyness">{{ text }}</p> ' +
      '</div>',
    replace: true,
    link: function($scope, $element, $attr) {
      $scope.text = $attr.text || '这里空空如也'
    }
  }
})

/**
 * @ngdoc    directive
 * @name     crm.services.directive:processbar
 * @element  ANY
 * @restrict ECMA
 * @description
 *   进度条控件
 */
.directive('processbar', function() {
  return {
    template: '<div class="processbar"> ' +
      '<div class="processbar-fill" style="width: {{ percent || 0 }}%; background-color: {{ color || \'red\' }}"></div>' +
      '</div>',
    replace: true,
    scope: {
      value: '@',
      color: '@'
    },
    link: function($scope) {
      $scope.$watch('value', function(val) {
        val = isNaN(+val) ? 0 : +val
        $scope.percent = Math.min(100, Math.max(val, 0))
      })
    }
  }
})

/* @ngInject */
.directive('ngCurrency', function($filter, $locale) {

  return {
    require: 'ngModel',
    link: function(scope, element, attrs, controller) {
      var hardCap, min, max, currencySymbol, ngRequired;
      var active = true;
      var fraction = 2;

      attrs.$observe('ngCurrency', function(value) {
        active = (value !== 'false');
        if (active) {
          reformat();
        } else {
          controller.$viewValue = controller.$$rawModelValue;
          controller.$render();
        }
      });

      attrs.$observe('hardCap', function(value) {
        hardCap = (value === 'true');
        revalidate();
      });
      attrs.$observe('min', function(value) {
        min = value ? Number(value) : undefined;
        revalidate();
      });
      attrs.$observe('max', function(value) {
        max = value ? Number(value) : undefined;
        revalidate();
      });
      attrs.$observe('currencySymbol', function(value) {
        currencySymbol = value;
        reformat();
      });
      attrs.$observe('ngRequired', function(value) {
        ngRequired = value;
        revalidate();
      });
      attrs.$observe('fraction', function(value) {
        fraction = value || 2;
        reformat();
        revalidate();
      });

      controller.$parsers.push(function(value) {
        if (active && [undefined, null, ''].indexOf(value) === -1) {
          value = clearValue(value);
          value = keepInRange(Number(value));
          return value;
        }
        return value;
      });

      controller.$formatters.push(function(value) {
        if (active && [undefined, null, ''].indexOf(value) === -1) {
          return $filter('currency')(value, getCurrencySymbol(), fraction);
        }
        return value;
      });

      controller.$validators.min = function(value) {
        if (!ngRequired && ([undefined, null, ''].indexOf(value) !== -1 || isNaN(value))) {
          return true;
        }
        return !active ||
          [undefined, null].indexOf(min) !== -1 || isNaN(min) ||
          value >= min;
      };

      controller.$validators.max = function(value) {
        if (!ngRequired && ([undefined, null, ''].indexOf(value) !== -1 || isNaN(value))) {
          return true;
        }
        return !active ||
          [undefined, null].indexOf(max) !== -1 || isNaN(max) ||
          value <= max;
      };

      controller.$validators.fraction = function(value) {
        return !active || !value || !isNaN(value);
      };

      function reformat() {
        if (active) {
          var value;
          if (controller.$options && controller.$options.updateOn === 'blur') {
            value = controller.$viewValue;
            for (var i = controller.$parsers.length - 1; i >= 0; i--) {
              value = controller.$parsers[i](value);
            }
          } else {
            value = controller.$$rawModelValue;
          }
          for (var i = controller.$formatters.length - 1; i >= 0; i--) {
            value = controller.$formatters[i](value);
          }
          controller.$viewValue = value;
          controller.$render();
        }
      }

      function revalidate() {
        controller.$validate();
        if (active) {
          var value = keepInRange(controller.$$rawModelValue);
          if (value !== controller.$$rawModelValue) {
            controller.$setViewValue(value.toFixed(fraction));
            controller.$commitViewValue();
            reformat();
          }
        }
      }

      function keepInRange(value) {
        if (hardCap) {
          if (max !== undefined && value > max) {
            value = max;
          } else if (min !== undefined && value < min) {
            value = min;
          }
        }
        return value;
      }

      scope.$on('currencyRedraw', function() {
        revalidate();
        reformat();
      });

      element.bind('focus', function() {
        if (active) {
          var groupRegex = new RegExp('\\' + $locale.NUMBER_FORMATS.GROUP_SEP, 'g');
          var value = [undefined, null, ''].indexOf(controller.$$rawModelValue) === -1 ? $filter('number')(controller.$$rawModelValue, fraction).replace(groupRegex, '') : controller.$$rawModelValue;
          if (controller.$viewValue !== value) {
            controller.$viewValue = value;
            controller.$render();
            element.triggerHandler('focus');
          }
        }
      });

      element.bind('blur', reformat);

      // TODO: Rewrite this parsing logic to more readable.

      function decimalRex(dChar) {
        return RegExp('\\d|\\-|\\' + dChar, 'g');
      }

      function clearRex(dChar) {
        return RegExp('\\-{0,1}((\\' + dChar + ')|([0-9]{1,}\\' + dChar + '?))&?[0-9]{0,' + fraction + '}', 'g');
      }

      function clearValue(value) {
        value = String(value);
        var dSeparator = $locale.NUMBER_FORMATS.DECIMAL_SEP;
        var cleared = null;

        if (value.indexOf($locale.NUMBER_FORMATS.DECIMAL_SEP) === -1 &&
          value.indexOf('.') !== -1 &&
          fraction > 0) {
          dSeparator = '.';
        }

        // Replace negative pattern to minus sign (-)
        var neg_dummy = $filter('currency')('-1', getCurrencySymbol(), fraction);
        var neg_regexp = RegExp('[0-9.' + $locale.NUMBER_FORMATS.DECIMAL_SEP + $locale.NUMBER_FORMATS.GROUP_SEP + ']+');
        var neg_dummy_txt = neg_dummy.replace(neg_regexp.exec(neg_dummy), '');
        var value_dummy_txt = value.replace(neg_regexp.exec(value), '');

        // If is negative
        if (neg_dummy_txt === value_dummy_txt) {
          value = '-' + neg_regexp.exec(value);
        }

        if (RegExp('^-[\\s]*$', 'g').test(value)) {
          value = '-0';
        }

        if (decimalRex(dSeparator).test(value)) {
          cleared = value.match(decimalRex(dSeparator))
            .join('').match(clearRex(dSeparator));
          cleared = cleared ? cleared[0].replace(dSeparator, '.') : null;
        }

        return cleared;
      }

      function getCurrencySymbol() {
        return currencySymbol === undefined ? $locale.NUMBER_FORMATS.CURRENCY_SYM : currencySymbol;
      }
    }
  };
})

.filter('crmFilterSelectedText', function() {
  return function(filterGroups) {
    var hasSelectedGroups = filterGroups.filter(function(g) {
      return g.selected !== 0
    })
    return hasSelectedGroups.map(function(g) {
      var text = g.items[g.selected].text
      if(g.groupName === '创建时间') {
        text += '创建'
      } else if(g.groupName === '跟进时间') {
        text += '跟进'
      }
      return text
    }).join(' ● ')
  }
})

.filter('crmContactExtendText', function(CRM_CONTACT_EXTEND) {
  return function(key) {
    return CRM_CONTACT_EXTEND[key] || ''
  }
})